package com.thiswhyme.common.utils;

import com.thiswhyme.common.conststant.CommonConstant;
import com.thiswhyme.common.expection.BusinessException;
import com.thiswhyme.common.response.ResponseCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.net.www.protocol.file.FileURLConnection;

import java.io.*;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @description: jar包内文件copy工具
 * @author: thiswhyme
 * @date: 2021/9/13
 */
public class JarFileCopyUtils {

    private static final Logger log = LoggerFactory.getLogger(JarFileCopyUtils.class);

    /**
     * 拷贝clazz所在jar中指定文件夹下文件
     * @param clazz
     * @param folderPath
     * @throws IOException
     */
    public static void loadRecourseFromJarByFolder(Class clazz, String folderPath, String targetPath) {
        try {
            URL url = clazz.getResource(folderPath);
            URLConnection urlConnection = url.openConnection();
            if (urlConnection instanceof FileURLConnection) {
                copyFileResources(url, folderPath, targetPath, clazz);
            } else if (urlConnection instanceof JarURLConnection) {
                copyJarResources((JarURLConnection)urlConnection, targetPath, clazz);
            }
        } catch (IOException e) {
            log.error("文件拷贝失败，folderPath：{}，targetPath：{}", folderPath, targetPath, e);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件拷贝失败");
        }
    }

    /**
     * 从jar内拷贝文件
     * @param clazz
     * @param path
     * @param targetPath
     * @throws IOException
     */
    public static void loadRecourseFromJar(Class clazz, String path, String targetPath) {
        if (!path.startsWith(CommonConstant.SLASH) || path.endsWith(CommonConstant.SLASH)) {
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件路径格式不正确");
        }

        // 创建目标文件夹
        int index = path.lastIndexOf('/');
        String filename = path.substring(index + 1);
        String folderPath = targetPath + path.substring(0, index + 1);
        File dir = new File(folderPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 创建目标文件
        filename = folderPath + filename;
        File file = new File(filename);
        if(file.exists()) {
            log.info("文件【{}】已存在，跳过复制", file.getAbsolutePath());
            return;
        }
        try {
            if (!file.createNewFile()) {
                throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件创建失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 获取待拷贝文件
        URL url = clazz.getResource(path);
        URLConnection urlConnection;
        try {
            urlConnection = url.openConnection();
        } catch (IOException e) {
            log.error("获取待拷贝文件失败，文件路径：{}", url.getPath());
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "获取待拷贝文件失败");
        }

        // 执行拷贝
        try(OutputStream os = new FileOutputStream(file); InputStream is = urlConnection.getInputStream()) {
            if (is == null) {
                throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件不存在");
            }
            byte[] buffer = new byte[1024];
            int readBytes;
            while ((readBytes = is.read(buffer)) != -1) {
                os.write(buffer, 0, readBytes);
            }
        } catch (IOException e) {
            log.error("文件拷贝失败", e);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件拷贝失败");
        }
    }

    /**
     * 当前运行环境资源文件在文件里
     * @param url
     * @param folderPath
     * @param clazz
     * @throws IOException
     */
    private static void copyFileResources(URL url, String folderPath, String targetPath, Class clazz) {
        File root = new File(url.getPath());
        if (root.isDirectory()) {
            File[] files = root.listFiles();
            for (File file : files) {
                if (file.isDirectory()) {
                    loadRecourseFromJarByFolder(clazz, folderPath + CommonConstant.SLASH +
                            file.getName(), targetPath);
                } else {
                    loadRecourseFromJar(clazz, folderPath + CommonConstant.SLASH + file.getName(), targetPath);
                }
            }
        }
    }

    /**
     * 当前运行环境资源文件在jar里
     * @param jarURLConnection
     * @throws IOException
     */
    private static void copyJarResources(JarURLConnection jarURLConnection, String targetPath,
                                         Class clazz) throws IOException {
        JarFile jarFile = jarURLConnection.getJarFile();
        Enumeration<JarEntry> entrys = jarFile.entries();
        while (entrys.hasMoreElements()) {
            JarEntry entry = entrys.nextElement();
            if (entry.getName().startsWith(jarURLConnection.getEntryName()) &&
                    !entry.getName().endsWith(CommonConstant.SLASH)) {
                loadRecourseFromJar(clazz, CommonConstant.SLASH + entry.getName(), targetPath);
            }
        }
        jarFile.close();
    }
}
